using System.IdentityModel.Tokens.Jwt;
using HamsterDocs.Domains.Storage;
using HamsterDocs.Domains.Users;
using HamsterDocs.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace HamsterDocs.Hosting.Services;

public class UsersService
{
    [Authorize(Policy = "User")]
    [HttpPut("/profile")]
    public ActionResult<ProfileResponse> UpdateProfile(
        [FromBody] ProfileRequest req,
        [FromServices] IContext context,
        [FromServices] IHttpContextAccessor accessor)
    {
        if (req is null)
        {
            return new BadRequestObjectResult(new { error = "InvalidRequest" });
        }

        var principal = accessor.HttpContext?.User;
        var sub = principal?.FindFirst(JwtRegisteredClaimNames.Sub)?.Value
                  ?? principal?.FindFirst("sub")?.Value;
        if (string.IsNullOrWhiteSpace(sub) || !Guid.TryParse(sub, out var userId))
        {
            return new UnauthorizedResult();
        }

        var db = (DbContext)context;
        var user = db.Set<User>().FirstOrDefault(x => x.Id == userId);
        if (user == null)
        {
            return new UnauthorizedResult();
        }

        // Validate uniqueness
        if (!string.IsNullOrWhiteSpace(req.UserName))
        {
            var existsName = db.Set<User>()
                .AsNoTracking()
                .Any(x => x.UserName == req.UserName && x.Id != userId);
            if (existsName)
            {
                return new BadRequestObjectResult(new { error = "UserNameExists" });
            }
            user.UserName = req.UserName;
        }

        if (!string.IsNullOrWhiteSpace(req.Email))
        {
            var existsEmail = db.Set<User>()
                .AsNoTracking()
                .Any(x => x.Email == req.Email && x.Id != userId);
            if (existsEmail)
            {
                return new BadRequestObjectResult(new { error = "EmailExists" });
            }
            user.Email = req.Email;
        }

        db.SaveChanges();

        var defaultRoute = (user.Role ?? "User") == "Admin" ? "/admin" : "/panel";
        return new OkObjectResult(new ProfileResponse(
            user.Id,
            user.UserName ?? string.Empty,
            user.Email ?? string.Empty,
            user.Role ?? "User",
            user.Avatar ?? string.Empty,
            defaultRoute
        ));
    }

    [Authorize(Policy = "User")]
    [HttpPut("/avatar")]
    public async Task<ActionResult<AvatarResponse>> UpdateAvatar(
        [FromForm] IFormFile file,
        [FromServices] IConfiguration configuration,
        [FromServices] IContext context,
        [FromServices] ImageService imageService,
        [FromServices] IHttpContextAccessor accessor)
    {
        if (file == null || file.Length <= 0)
        {
            return new BadRequestObjectResult(new { error = "EmptyFile" });
        }

        var principal = accessor.HttpContext?.User;
        var sub = principal?.FindFirst(JwtRegisteredClaimNames.Sub)?.Value
                  ?? principal?.FindFirst("sub")?.Value;
        if (string.IsNullOrWhiteSpace(sub) || !Guid.TryParse(sub, out var userId))
        {
            return new UnauthorizedResult();
        }

        var storageRoot = configuration.GetSection("Storage")["Root"] ?? "./storage";

        var result = await imageService.SaveAvatarAsync(file, userId, storageRoot);

        var db = (DbContext)context;

        // Save storage record
        var storage = new LocalStorage
        {
            Name = file.FileName,
            ContentType = file.ContentType,
            Site = 0,
            UserId = userId,
            Path = result.OriginalWebPath,
            ThumbPath = result.ThumbWebPath,
            FileHash = result.FileHash,
            Width = result.Width,
            Height = result.Height,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };
        db.Set<LocalStorage>().Add(storage);

        // Update user avatar to thumbnail
        var user = db.Set<User>().FirstOrDefault(x => x.Id == userId);
        if (user == null)
        {
            return new UnauthorizedResult();
        }
        user.Avatar = result.ThumbWebPath;

        await db.SaveChangesAsync();

        return new OkObjectResult(new AvatarResponse(user.Avatar ?? string.Empty));
    }

    public record ProfileRequest(string? UserName, string? Email);
    public record ProfileResponse(Guid Id, string UserName, string Email, string Role, string Avatar, string DefaultRoute);
    public record AvatarResponse(string Avatar);
}